home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Magazine / Online / QMail / source / qmail-pop3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-15  |  7.8 KB  |  398 lines

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include "direntry.h"
  4. #include "sig.h"
  5. #include "getln.h"
  6. #include "stralloc.h"
  7. #include "substdio.h"
  8. #include "alloc.h"
  9. #include "datetime.h"
  10. #include "prot.h"
  11. #include "open.h"
  12. #include "prioq.h"
  13. #include "scan.h"
  14. #include "fmt.h"
  15. #include "error.h"
  16. #include "str.h"
  17. #include "exit.h"
  18. #include "now.h"
  19. #include "readwrite.h"
  20.  
  21. int timeout = 1200;
  22.  
  23. char ssoutbuf[1024];
  24. substdio ssout = SUBSTDIO_FDBUF(write,1,ssoutbuf,sizeof(ssoutbuf));
  25.  
  26. int timeoutread(fd,buf,n) int fd; char *buf; int n;
  27. {
  28.  int r; int saveerrno;
  29.  alarm(timeout);
  30.  r = read(fd,buf,n); saveerrno = errno;
  31.  alarm(0);
  32.  errno = saveerrno; return r;
  33. }
  34.  
  35. char ssinbuf[128];
  36. substdio ssin = SUBSTDIO_FDBUF(timeoutread,0,ssinbuf,sizeof(ssinbuf));
  37.  
  38.  
  39. void die() { _exit(0); }
  40. void puts(s) char *s;
  41. {
  42.  if (substdio_puts(&ssout,s) == -1) die();
  43. }
  44. void flush()
  45. {
  46.  if (substdio_flush(&ssout) == -1) die();
  47. }
  48. void err(s) char *s;
  49. {
  50.  puts("-ERR ");
  51.  puts(s);
  52.  puts("\r\n");
  53.  if (substdio_flush(&ssout) == -1) die();
  54. }
  55. void die_nomem() { err("out of memory"); die(); }
  56. void die_prot() { err("protection problem"); die(); }
  57. void die_nomaildir() { err("this user has no $HOME/Maildir"); die(); }
  58.  
  59. void err_syntax() { err("syntax error"); }
  60. void err_unimpl() { err("unimplemented"); }
  61. void err_deleted() { err("already deleted"); }
  62. void err_nozero() { err("messages are counted from 1"); }
  63. void err_toobig() { err("not that many messages"); }
  64. void err_nosuch() { err("unable to open that message"); }
  65. void err_nounlink() { err("unable to unlink all deleted messages"); }
  66.  
  67. void okay() { puts("+OK \r\n"); flush(); }
  68. void pop3_last() { puts("+OK 0\r\n"); flush(); }
  69.  
  70.  
  71. stralloc dataline = {0};
  72.  
  73. stralloc filenames = {0};
  74. prioq pq = {0};
  75. stralloc newname = {0};
  76.  
  77. struct message
  78.  {
  79.   int flagdeleted;
  80.   unsigned long size;
  81.   char *fn;
  82.  }
  83. *m;
  84. int numm;
  85.  
  86. substdio ssmsg; char ssmsgbuf[1024];
  87.  
  88.  
  89. void blast(ssfrom,limit)
  90. substdio *ssfrom;
  91. unsigned long limit;
  92. {
  93.  int match;
  94.  int inheaders = 1;
  95.  
  96.  for (;;)
  97.   {
  98.    if (getln(ssfrom,&dataline,&match,'\n') != 0) die();
  99.    if (!match && !dataline.len) break;
  100.    if (match) --dataline.len; /* no way to pass this info over POP */
  101.    if (limit) if (!inheaders) if (!--limit) break;
  102.    if (!dataline.len)
  103.      inheaders = 0;
  104.    else
  105.      if (dataline.s[0] == '.')
  106.        substdio_put(&ssout,".",1);
  107.    if (substdio_put(&ssout,dataline.s,dataline.len) == -1) die();
  108.    if (substdio_put(&ssout,"\r\n",2) == -1) die();
  109.    if (!match) break;
  110.   }
  111.  if (substdio_put(&ssout,"\r\n.\r\n",5) == -1) die();
  112.  if (substdio_flush(&ssout) == -1) die();
  113. }
  114.  
  115. void getlist()
  116. {
  117.  unsigned long pos;
  118.  datetime_sec time;
  119.  DIR *dir;
  120.  direntry *d;
  121.  struct prioq_elt pe;
  122.  struct stat st;
  123.  int i;
  124.  
  125.  numm = 0;
  126.  
  127.  time = now();
  128.  
  129.  if (dir = opendir("tmp"))
  130.   {
  131.    while (d = readdir(dir))
  132.     {
  133.      if (str_equal(d->d_name,".")) continue;
  134.      if (str_equal(d->d_name,"..")) continue;
  135.      if (!stralloc_copys(&newname,"tmp/")) die_nomem();
  136.      if (!stralloc_cats(&newname,d->d_name)) die_nomem();
  137.      if (!stralloc_0(&newname)) die_nomem();
  138.      if (stat(newname.s,&st) == 0)
  139.        if (time > st.st_atime + 129600)
  140.      unlink(newname.s);
  141.     }
  142.    closedir(dir);
  143.   }
  144.  
  145.  if (!stralloc_copys(&filenames,"")) die_nomem();
  146.  
  147.  if (dir = opendir("new"))
  148.   {
  149.    while (d = readdir(dir))
  150.     {
  151.      if (str_equal(d->d_name,".")) continue;
  152.      if (str_equal(d->d_name,"..")) continue;
  153.      pos = filenames.len;
  154.      if (!stralloc_cats(&filenames,"new/")) die_nomem();
  155.      if (!stralloc_cats(&filenames,d->d_name)) die_nomem();
  156.      if (!stralloc_0(&filenames)) die_nomem();
  157.      if (stat(filenames.s + pos,&st) == 0)
  158.       {
  159.        pe.dt = st.st_mtime;
  160.        pe.id = pos;
  161.        if (!prioq_insert(&pq,&pe)) die_nomem();
  162.        ++numm;
  163.       }
  164.     }
  165.    closedir(dir);
  166.   }
  167.  
  168.  if (dir = opendir("cur"))
  169.   {
  170.    while (d = readdir(dir))
  171.     {
  172.      if (str_equal(d->d_name,".")) continue;
  173.      if (str_equal(d->d_name,"..")) continue;
  174.      pos = filenames.len;
  175.      if (!stralloc_cats(&filenames,"cur/")) die_nomem();
  176.      if (!stralloc_cats(&filenames,d->d_name)) die_nomem();
  177.      if (!stralloc_0(&filenames)) die_nomem();
  178.      if (stat(filenames.s + pos,&st) == 0)
  179.       {
  180.        pe.dt = st.st_mtime;
  181.        pe.id = pos;
  182.        if (!prioq_insert(&pq,&pe)) die_nomem();
  183.        ++numm;
  184.       }
  185.     }
  186.    closedir(dir);
  187.   }
  188.  
  189.  m = (struct message *) alloc(numm * sizeof(struct message));
  190.  if (!m) die_nomem();
  191.  
  192.  for (i = 0;i < numm;++i)
  193.   {
  194.    if (!prioq_min(&pq,&pe)) { numm = i; break; }
  195.    prioq_delmin(&pq);
  196.    m[i].fn = filenames.s + pe.id;
  197.    m[i].flagdeleted = 0;
  198.    if (stat(m[i].fn,&st) == -1)
  199.      m[i].size = 0;
  200.    else
  201.      m[i].size = st.st_size;
  202.   }
  203. }
  204.  
  205. char foo[FMT_ULONG];
  206.  
  207. void printint(u) unsigned int u;
  208. {
  209.  foo[fmt_uint(foo,u)] = 0;
  210.  puts(foo);
  211.  puts(" ");
  212. }
  213.  
  214. void printlong(u) unsigned long u;
  215. {
  216.  foo[fmt_uint(foo,u)] = 0;
  217.  puts(foo);
  218.  puts("\r\n");
  219. }
  220.  
  221. void printfn(fn) char *fn;
  222. {
  223.  puts(fn + 4);
  224.  puts("\r\n");
  225. }
  226.  
  227. void pop3_stat()
  228. {
  229.  int i;
  230.  unsigned long total;
  231.  
  232.  total = 0;
  233.  for (i = 0;i < numm;++i) if (!m[i].flagdeleted) total += m[i].size;
  234.  puts("+OK ");
  235.  printint(numm);
  236.  printlong(total);
  237.  flush();
  238. }
  239.  
  240. void pop3_rset()
  241. {
  242.  int i;
  243.  for (i = 0;i < numm;++i) m[i].flagdeleted = 0;
  244.  okay();
  245. }
  246.  
  247. void pop3_quit()
  248. {
  249.  int i;
  250.  for (i = 0;i < numm;++i)
  251.    if (m[i].flagdeleted)
  252.      if (unlink(m[i].fn) == -1) err_nounlink();
  253.  okay();
  254.  die();
  255. }
  256.  
  257. int msgno(arg) char *arg;
  258. {
  259.  unsigned long u;
  260.  if (!arg) { err_syntax(); return -1; }
  261.  if (!scan_ulong(arg,&u)) { err_syntax(); return -1; }
  262.  if (!u) { err_nozero(); return -1; }
  263.  --u;
  264.  if (u >= numm) { err_toobig(); return -1; }
  265.  if (m[u].flagdeleted) { err_deleted(); return -1; }
  266.  return u;
  267. }
  268.  
  269. void pop3_dele(arg) char *arg;
  270. {
  271.  int i;
  272.  
  273.  i = msgno(arg);
  274.  if (i == -1) return;
  275.  m[i].flagdeleted = 1;
  276.  okay();
  277. }
  278.  
  279. void dolisting(arg,flaguidl) char *arg; int flaguidl;
  280. {
  281.  unsigned int i;
  282.  
  283.  if (arg)
  284.   {
  285.    i = msgno(arg);
  286.    if (i == -1) return;
  287.    puts("+OK ");
  288.    printint(i + 1);
  289.    if (flaguidl) printfn(m[i].fn); else printlong(m[i].size);
  290.   }
  291.  else
  292.   {
  293.    okay();
  294.  
  295.    for (i = 0;i < numm;++i)
  296.      if (!m[i].flagdeleted)
  297.       {
  298.        printint(i + 1);
  299.        if (flaguidl) printfn(m[i].fn); else printlong(m[i].size);
  300.       }
  301.    puts(".\r\n");
  302.   }
  303.  flush();
  304. }
  305.  
  306. void pop3_uidl(arg) char *arg; { dolisting(arg,1); }
  307. void pop3_list(arg) char *arg; { dolisting(arg,0); }
  308.  
  309. void pop3_top(arg) char *arg;
  310. {
  311.  int i;
  312.  unsigned long limit;
  313.  int fd;
  314.  
  315.  i = msgno(arg);
  316.  if (i == -1) return;
  317.  
  318.  arg += scan_ulong(arg,&limit);
  319.  while (*arg == ' ') ++arg;
  320.  if (scan_ulong(arg,&limit)) ++limit; else limit = 0;
  321.  
  322.  fd = open_read(m[i].fn);
  323.  if (fd == -1) { err_nosuch(); return; }
  324.  okay();
  325.  substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf));
  326.  blast(&ssmsg,limit);
  327.  close(fd);
  328. }
  329.  
  330. static struct { void (*fun)(); char *text; } pop3cmd[] = {
  331.   { pop3_quit, "quit" }
  332. , { pop3_stat, "stat" }
  333. , { pop3_list, "list" }
  334. , { pop3_uidl, "uidl" }
  335. , { pop3_dele, "dele" }
  336. , { pop3_top, "retr" }
  337. , { pop3_rset, "rset" }
  338. , { pop3_last, "last" }
  339. , { pop3_top, "top" }
  340. , { okay, "noop" }
  341. , { 0, 0 }
  342. };
  343.  
  344. void doit(cmd)
  345. char *cmd;
  346. {
  347.  int i;
  348.  int j;
  349.  char ch;
  350.  
  351.  for (i = 0;pop3cmd[i].fun;++i)
  352.   {
  353.    for (j = 0;ch = pop3cmd[i].text[j];++j)
  354.      if ((cmd[j] != ch) && (cmd[j] != ch - 32))
  355.        break;
  356.    if (!ch)
  357.      if (!cmd[j] || (cmd[j] == ' '))
  358.       {
  359.        while (cmd[j] == ' ') ++j;
  360.        if (!cmd[j])
  361.          pop3cmd[i].fun((char *) 0);
  362.        else
  363.          pop3cmd[i].fun(cmd + j);
  364.        return;
  365.       }
  366.   }
  367.  err_unimpl();
  368. }
  369.  
  370. void main(argc,argv)
  371. int argc;
  372. char **argv;
  373. {
  374.  static stralloc cmd = {0};
  375.  int match;
  376.  
  377.  sig_alarmcatch(die);
  378.  sig_pipeignore();
  379.  
  380.  if (!argv[1]) die_nomaildir();
  381.  if (chdir(argv[1]) == -1) die_nomaildir();
  382.  
  383.  getlist();
  384.  
  385.  okay();
  386.  
  387.  for (;;)
  388.   {
  389.    if (getln(&ssin,&cmd,&match,'\n') == -1) die();
  390.    if (!match) die();
  391.    if (cmd.len == 0) die();
  392.    if (cmd.s[--cmd.len] != '\n') die();
  393.    if ((cmd.len > 0) && (cmd.s[cmd.len - 1] == '\r')) --cmd.len;
  394.    cmd.s[cmd.len++] = 0;
  395.    doit(cmd.s);
  396.   }
  397. }
  398.